/********************************************************************************
* @file    os_api.h
* @author  jianqiang.xue
* @version V1.1.0
* @date    2023-03-01
* @brief   NULL
********************************************************************************/
#ifndef __OS_API_H
#define __OS_API_H
#include <stdint.h>
#include <stdbool.h>
#include "cmsis_os.h"
#include "cmsis_compiler.h"

/// Timeout value.
#define OS_WAIT_FOREVER     0xFFFFFFFFU    ///< wait forever timeout value

/************************************OS_KERNEL************************************/
typedef enum {
    OS_OK                     =     0,       ///< function completed; no error or event occurred.
    OS_EVENT_SIGNAL           =  0x08,       ///< function completed; signal event occurred.
    OS_EVENT_MESSAGE          =  0x10,       ///< function completed; message event occurred.
    OS_EVENT_MAIL             =  0x20,       ///< function completed; mail event occurred.
    OS_EVENT_TIMEOUT          =  0x40,       ///< function completed; timeout occurred.
    OS_ERROR_PARAMETER        =  0x80,       ///< parameter error: a mandatory parameter was missing or specified an incorrect object.
    OS_ERROR_RESOURCE         =  0x81,       ///< resource not available: a specified resource was not available.
    OS_ERROR_TIMEOUTRESOURCE  =  0xC1,       ///< resource not available within given time: a specified resource was not available within the timeout period.
    OS_ERROR_ISR              =  0x82,       ///< not allowed in ISR context: the function cannot be called from interrupt service routines.
    OS_ERROR_ISRRECURSIVE     =  0x83,       ///< function called multiple times from ISR with same object.
    OS_ERROR_PRIORITY         =  0x84,       ///< system cannot determine priority or thread has illegal priority.
    OS_ERROR_NOMEMORY         =  0x85,       ///< system is out of memory: it was impossible to allocate or reserve memory for the operation.
    OS_ERROR_VALUE            =  0x86,       ///< value of a parameter is out of range.
    OS_ERROR_OS               =  0xFF,       ///< unspecified RTOS error: run-time error but no other error message fits.
    // RTX
    os_Error                  = -1,         ///< Unspecified RTOS error: run-time error but no other error message fits.
    os_Error_Timeout          = -2,         ///< Operation not completed within the timeout period.
    os_Error_Resource         = -3,         ///< Resource not available.
    os_Error_Parameter        = -4,         ///< Parameter error.
    os_Error_NoMemory         = -5,         ///< System is out of memory: it was impossible to allocate or reserve memory for the operation.
    os_Error_ISR              = -6,         ///< Not allowed in ISR context: the function cannot be called from interrupt service routines.
    OS_STATUS_RESERVED        =  0x7FFFFFFF  ///< prevent from enum down-size compiler optimization.
} os_status;

os_status os_kernel_initialize (void);
os_status os_kernel_start(void);

// 禁止任务调度，不会禁止SysTick，如果用这个进入STOP模式，可能会导致定时器溢出
os_status os_kernel_lock(void);
os_status os_kernel_unlock(void);

// 禁止OS，禁止SysTick, 不会导致软定时器异常溢出
uint32_t os_kernel_stop(void);
void os_kernel_resume(uint32_t sleep_ticks);

os_status os_delay(uint32_t ms);
uint32_t os_get_tick(void);

//  Memory Pool Header structure
typedef struct {
  uint32_t size; // 最大内容量(Byte)
  uint32_t used; // 当前使用内存量(Byte)
} mem_info_t;

void* os_malloc(uint32_t size);
void* os_calloc(uint32_t size);
void os_free(void *p);
mem_info_t* os_get_memory_info(void);
/************************************OS_EVENT************************************/
typedef struct os_mailq_cb    *os_mail_qid;
typedef struct os_messageq_cb *os_message_qid;

typedef struct  {
    os_status                 status;     ///< status code: event or error information
    union  {
      uint32_t                    v;     ///< message as 32-bit value
      void                       *p;     ///< message or mail as void pointer
      int32_t               signals;     ///< signal flags
    } value;                             ///< event value
    union  {
      os_mail_qid             mail_id;   ///< mail id obtained by \ref osMailCreate
      os_message_qid       message_id;   ///< message id obtained by \ref osMessageCreate
    } def;                               ///< event definition
} os_event;

/************************************OS_THREAD************************************/
#ifndef FREERTOS
typedef enum {
    OS_PRIORITY_IDLE          = -3,          ///< priority: idle (lowest)
    OS_PRIORITY_LOW           = -2,          ///< priority: low
    OS_PRIORITY_BELOWNORMAL   = -1,          ///< priority: below normal
    OS_PRIORITY_NORMAL        =  0,          ///< priority: normal (default)
    OS_PRIORITY_ABOVENORMAL   = +1,          ///< priority: above normal
    OS_PRIORITY_HIGH          = +2,          ///< priority: high
    OS_PRIORITY_REALTIME      = +3,          ///< priority: realtime (highest)
    OS_PRIORITY_ERROR         =  0x84        ///< system cannot determine priority or thread has illegal priority
} os_priority_t;
#else
typedef enum {
    OS_PRIORITY_IDLE          = 0,          ///< priority: idle (lowest)
    OS_PRIORITY_LOW           = 1,          ///< priority: low
    OS_PRIORITY_BELOWNORMAL   = 2,          ///< priority: below normal
    OS_PRIORITY_NORMAL        = 3,          ///< priority: normal (default)
    OS_PRIORITY_ABOVENORMAL   = 4,          ///< priority: above normal
    OS_PRIORITY_HIGH          = 5,          ///< priority: high
    OS_PRIORITY_REALTIME      = 6,          ///< priority: realtime (highest)
    OS_PRIORITY_ERROR         = 0x84        ///< system cannot determine priority or thread has illegal priority
} os_priority_t;
#endif

typedef struct os_thread_cb *os_thread_id;
typedef void (*os_pthread) (void const *argument);

typedef struct {
    os_pthread             pthread;      ///< start address of thread function
    os_priority_t          tpriority;    ///< initial thread priority
    uint32_t               instances;    ///< maximum number of instances of that thread function
    uint32_t               stacksize;    ///< stack size requirements in bytes; 0 is default stack size
} os_thread_def_t;

#define os_thread(name)  &os_thread_def_##name

#define os_thread_def(name, priority, instances, stacksz)  \
const os_thread_def_t os_thread_def_##name = {(name), (priority), (instances), (stacksz)}

os_thread_id os_thread_create(const os_thread_def_t *thread_def, void *arg);

// 定义线程所需的变量和回调声明（请在全局区调用）
#define OS_THREAD_DECLARE(name, priority, stacksz)    \
    static void task_##name(void const *argument);    \
    os_thread_id task_##name##_id = NULL;             \
    os_thread_def(task_##name, priority, 1, stacksz);

// 创建线程(请在函数中使用)
#define OS_THREAD_CREATE(name) {                                       \
    task_##name##_id = os_thread_create(os_thread(task_##name), NULL); \
    if (!task_##name##_id) {                   \
        LOGE("thread create fail! %s", #name); \
        return 1;                              \
    }                                          \
}

/************************************OS_TIMER************************************/
typedef struct os_timer_cb *os_timer_id;
typedef void (*os_ptimer) (void const *argument);

typedef struct {
    os_ptimer ptimer; ///< start address of a timer function
    void *timer;      ///< pointer to internal data
} os_timer_def_t;

typedef enum {
    OS_TIMER_ONCE     = 0,    ///< one-shot timer
    OS_TIMER_PERIODIC = 1     ///< repeating timer
} os_timer_t;

#define os_timer(name) &os_timer_def_##name

#if (osCMSIS < 0x20000U)
#define os_timer_def(name, function)  static uint32_t os_timer_cb_##name[6] = {0};\
const os_timer_def_t os_timer_def_##name = {(function), ((void *)os_timer_cb_##name)}
#else
#define os_timer_def(name, function) static const uint8_t os_timer_cb_##name[10];\
static const os_timer_def_t os_timer_def_##name = {(function), ((void *)os_timer_cb_##name)}
#endif

os_timer_id os_timer_create(const os_timer_def_t *timer_def, os_timer_t type, void *arg);
os_status os_timer_start(os_timer_id timer_id, uint32_t millisec);
os_status os_timer_stop(os_timer_id timer_id);
bool os_timer_is_running(os_timer_id timer_id);
os_status os_timer_restart(os_timer_id timer_id, uint32_t millisec);
os_status os_timer_delete(os_timer_id timer_id);

#define OS_TIMER_ID(name) timer_##name##_id

// 定义软定时器所需的变量和回调声明（请在全局区调用）
#define OS_TIMER_DECLARE(name, cb)        \
    void cb(void const *arg);             \
    os_timer_id timer_##name##_id;        \
    os_timer_def(timer_##name, cb);

// 定义软定时器所需的变量和回调声明（请在全局区调用）使用默认回调
#define OS_TIMER_DECLARE_N(name)                    \
    static void timer_##name##_cb(void const *arg); \
    os_timer_id timer_##name##_id;                  \
    os_timer_def(timer_##name, timer_##name##_cb);

// 创建软定时器并指定周期类型(单次/循环)(请在函数中使用) OS_TIMER_ONCE/OS_TIMER_PERIODIC
#define OS_TIMER_CREATE(name, cycle_t) {      \
    timer_##name##_id = os_timer_create(os_timer(timer_##name), cycle_t, &timer_ret); \
    if (!timer_##name##_id) {                 \
        LOGE("timer create fail! %s", #name); \
        return 1;                             \
    }                                         \
}

// 启动软定时器(请在函数中使用)
#define OS_TIMER_START(name, ms) {                                  \
    if (timer_##name##_id) {                                        \
        uint32_t timer_ret = os_timer_start(timer_##name##_id, ms); \
        if (timer_ret != 0) {                                       \
            LOGE("timer start fail! %s,%d", #name, timer_ret);      \
        }                                                           \
    }                                                               \
}

#define OS_TIMER_RESTART(name, ms) {                                  \
    if (timer_##name##_id) {                                          \
        uint32_t timer_ret = os_timer_restart(timer_##name##_id, ms); \
        if (timer_ret != 0) {                                         \
            LOGE("timer restart fail! %s,%d", #name, timer_ret);      \
        }                                                             \
    }                                                                 \
}

// 停止软定时器(请在函数中使用)
#define OS_TIMER_STOP(name) {             \
    if (timer_##name##_id)                \
        os_timer_stop(timer_##name##_id); \
}

// 删除软定时器(请在函数中使用)
#define OS_TIMER_DEL(name) {                \
    if (timer_##name##_id) {                \
        os_timer_delete(timer_##name##_id); \
        timer_##name##_id = NULL;           \
    }                                       \
}

/************************************OS_MAIL************************************/
typedef struct os_mailq_cb *os_mail_qid;
#define os_mail_qdef(name, queue_sz, type)                                        \
    static const uint8_t os_mailq_q_##name[4 + (queue_sz)] = {0};                      \
    static const uint8_t os_mailq_m_##name[3 + ((sizeof(type) + 3) / 4) * (queue_sz)]; \
    static void *os_mailq_p_##name[2] = {(os_mailq_q_##name), os_mailq_m_##name}; \
    static const os_mailq_def_t os_mailq_def_##name = {(queue_sz), sizeof(type), (os_mailq_p_##name)} \

typedef struct os_mailq_def {
    uint16_t queue_sz; ///< number of elements in the queue
    uint16_t item_sz;  ///< size of an item
    void *pool;        ///< memory array for mail
} os_mailq_def_t;

#define os_mailq(name) &os_mailq_def_##name

os_mail_qid os_mail_create(const os_mailq_def_t *queue_def, os_thread_id thread_id);
void *os_mail_alloc(os_mail_qid queue_id, uint32_t millisec);
void *os_mail_clean_and_alloc(os_mail_qid queue_id, uint32_t millisec);
os_status os_mail_put(os_mail_qid queue_id, void *mail);
os_event os_mail_get(os_mail_qid queue_id, uint32_t millisec, void *arg);
os_status os_mail_free(os_mail_qid queue_id, void *mail);

/************************************OS_MSG_QUEUE************************************/
/// Message ID identifies the message queue (pointer to a message queue control block).
typedef struct os_messageq_cb *os_message_qid;
typedef struct os_messageq_def {
    uint32_t queue_sz;            ///< number of elements in the queue
#if (osCMSIS < 0x20000U)
    void *pool;                   ///< memory array for messages
#else
    osMessageQueueAttr_t  attr;   ///< message queue attributes
#endif
} os_messageq_def_t;

#if (osCMSIS < 0x20000U)
#define os_message_qdef(name, queue_sz, type)                        \
    static uint8_t os_messageq_q_##name[4 + (queue_sz)] = {0};       \
    static const os_messageq_def_t os_messageq_def_##name = {(queue_sz), ((void *)os_messageq_q_##name)}
#else
#define os_message_qdef(name, queue_sz, type)                        \
    static const os_messageq_def_t os_messageq_def_##name = {(queue_sz), { NULL, 0U, NULL, 0U, NULL, 0U }}
#endif

/// \brief Access a Message Queue Definition.
/// \param         name          name of the queue
#define os_messageq(name)  &os_messageq_def_##name

os_message_qid os_message_create(const os_messageq_def_t *queue_def, os_thread_id thread_id);
os_status os_message_put(os_message_qid queue_id, uint32_t info, uint32_t millisec);
os_event os_message_get(os_message_qid queue_id, uint32_t millisec);
uint8_t os_message_get_space(os_message_qid queue_id);
uint8_t os_message_get_count(os_message_qid queue_id);

// 定义消息队列所需的变量和回调声明（请在全局区调用）
#define OS_MSG_DECLARE(name, num, stacksz)         \
    static os_message_qid msg_##name##_qid = NULL; \
    os_message_qdef(msg_##name, num, stacksz);

// 创建消息队列(请在函数中使用)
#define OS_MSG_CREATE(name) {               \
    msg_##name##_qid = os_message_create(os_messageq(msg_##name), NULL); \
    if (!msg_##name##_qid) {                \
        LOGE("msg create fail! %s", #name); \
        return 1;                           \
    }                                       \
}

/************************************OS_POOL************************************/
/// Pool ID identifies the memory pool (pointer to a memory pool control block).
typedef struct os_pool_cb *os_pool_id;
typedef struct os_pool_deft {
    uint32_t pool_sz; ///< number of items (elements) in the pool
    uint32_t item_sz; ///< size of an item
    void *pool;       ///< pointer to memory for pool
} os_pool_def_t;

#if (osCMSIS < 0x20000U)
#define os_pool_def(name, num, type)                                                                   \
    static uint8_t os_pool_m_##name[3 + ((sizeof(type) + 3) / 4) * (num)];                             \
    static const os_pool_def_t os_pool_def_##name = {(num), sizeof(type), (void *)(os_pool_m_##name)}
#else
#define os_pool_def(name, num, type)                                                                   \
    static const uint8_t os_pool_m_##name[3 + ((sizeof(type) + 3) / 4) * (num)];                       \
    static const os_pool_def_t os_pool_def_##name = {(num), sizeof(type), (void *)(os_pool_m_##name)}
#endif
#define os_pool(name)  &os_pool_def_##name

os_pool_id os_pool_create(const os_pool_def_t *pool_def);
void *os_pool_alloc(os_pool_id pool_id);
void *os_pool_calloc(os_pool_id pool_id);
os_status os_pool_free(os_pool_id pool_id, void *block);
uint8_t os_pool_get_space(os_pool_id pool_id);

// 定义内存池所需的变量和回调声明（请在全局区调用）
#define OS_POOL_DECLARE(name, num, stacksz)    \
    static os_pool_id pool_##name##_id = NULL; \
    os_pool_def(pool_##name, num, stacksz);

// 创建内存池(请在函数中使用)
#define OS_POOL_CREATE(name) {                               \
    pool_##name##_id = os_pool_create(os_pool(pool_##name)); \
    if (!pool_##name##_id) {                                 \
        LOGE("pool create fail! %s", #name);                 \
        return 1;                                            \
    }                                                        \
}
/************************************OS_SIGNAL************************************/
int32_t isr_signal_set(os_thread_id thread_id, int32_t signals);
int32_t os_signal_set(os_thread_id thread_id, int32_t signals);
int32_t os_signal_clear(os_thread_id thread_id, int32_t signals);
os_event os_signal_wait(int32_t signals, uint32_t millisec);

/*********************************OS_Mutex(互斥锁)********************************/
typedef void *os_mutex_id;

typedef struct { // 互斥锁的属性结构。
    const char* name;    // 互斥对象的名称
    uint32_t attr_bits;  // 属性位
    void* cb_mem;        // 控制块内存指针
    uint32_t cb_size;    // 为控制块提供的内存大小
} os_mutex_attr_t;
os_mutex_id os_mutex_new(const os_mutex_attr_t* mutex_attr);
os_status os_mutex_get(os_mutex_id mutex_id, uint32_t timeout);
os_status os_mutex_release(os_mutex_id mutex_id);
os_status os_mutex_delete(os_mutex_id mutex_id);

#ifdef FREERTOS
void get_task_info(void);
#endif
#endif
